package de.rs.espresso.algorithms.minimumcover.model;

import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;

public class Row implements Cloneable {
	
	private int rowNumber;
	
	private BitSet element;
	
	public Row(BitSet element, int rowNumber) {
		this.element = element;
		this.rowNumber = rowNumber;
	}
	
	private Row(Row r, List<Integer> removableColumns, int columnCount) {
		
		rowNumber = r.rowNumber;
		element = new BitSet(columnCount-removableColumns.size());
		
		int nextBit = 0;
		for(int count = 0; count<columnCount; count++) {
			if(!removableColumns.contains(count)) {
				if(r.getElement().get(count))
					element.set(nextBit);
				nextBit++;
			}
		}
	}
	
	private Row(Row r, int removableColumn) {
		
		rowNumber = r.rowNumber;
		element = new BitSet(r.element.size()-1);
		
		int nextBit = 0;
		for(int count = 0; count<r.element.size(); count++) {
			if(removableColumn != count) {
				element.set(nextBit++);				
			}
		}
	}
	
	public static Row removeColumns(Row r, List<Integer> removableColumns, int columnCount) {
		return new Row(r, removableColumns, columnCount);
	}
	
	public static Row removeColumn(Row r,  int removableColumn) {
		return new Row(r, removableColumn);
	}


	public static List<Row> toRowList(List<BitSet> rows) {
		List<Row> result = new ArrayList<Row>();
		
		int rowNumber = 0;
		for(BitSet r : rows) {
			result.add(new Row(r, rowNumber));
			rowNumber++;
		}
		
		return result;
		
	}

	public boolean intersects(Row otherRow) {
		return this.element.intersects(otherRow.getElement());
	}
	
	public BitSet getElement() {
		return element;
	}

	public int cardinality() {
		return element.cardinality();
	}

	public boolean covers(Row row) {
		BitSet elementClone = element.get(0, element.size()-1);
		elementClone.or(row.element);
		return element.equals(elementClone);
	}

	public int getPosition() {
		return rowNumber;
	}
	
	
	public static Row rotateRow(List<Row> rows, int columnNumber) {
		BitSet newElement = new BitSet(rows.size());
		for(Row r : rows) {
			newElement.set(r.getPosition(), r.getElement().get(columnNumber));
		}
		return new Row(newElement, columnNumber);
		
	}
	
	public static List<Row> rotateRows(List<Row> rows, int maxCount) {
		List<Row> result = new ArrayList<Row>();
		if(!rows.isEmpty()) {
			for(int count = 0; count<maxCount; count++) {
				result.add(rotateRow(rows,count));
			}
				
		}
		return result;
	}

	public int getEssentialColumnNumber() {
		return element.nextSetBit(0);
		
	}

	public double getWeight(int position) {
		if(element.get(position))
			return 1/element.cardinality();
		return 0;
	}
	
	public Row clone() {
		
		BitSet clonedBitSet = new BitSet(element.size());
		for(int count = 0 ; count<element.size(); count ++)
			clonedBitSet.set(count, element.get(count));
		
		return new Row(clonedBitSet, rowNumber);
		
	}
	

}
